/*
 * freefuncs.cpp
 *
 *  Created on: Feb 26, 2011
 *      Author: Mo
 */
//#pragma once
#include "freefuncs.h"
#include <iostream>
#include <stdexcept>

using namespace std;


int countBorders (int** matrix, int rowNum, int colNum)
{
	int result = 0;
	for (int row = 0; row!= rowNum; row++)
		for (int col = 0; col != colNum; col++)
		{
			if (row != 0)
				if ( matrix[row][col] == 1 && matrix[row-1][col] == 0)
					result++;
			if (col != colNum-1)
				if ( matrix[row][col] == 1 && matrix[row][col+1] == 0)
					result++;
			if (row != rowNum-1)
				if ( matrix[row][col] == 1 && matrix[row+1][col] == 0)
					result++;
			if (col != 0)
				if ( matrix[row][col] == 1 && matrix[row][col-1] == 0)
					result++;
		}
	return result;
}

int countNonZeros (int matrix[][MCOLS], int rowNum, int colNum)
{
	int result = 0;
	for (int row = 0; row!= rowNum; row++)
		for (int col = 0; col != colNum; col++)
			if (matrix[row][col] != 0)
				result++;
	return result;
}

int intPosPow (int a, int b)
{
	int result = 1;
	if (b < 0)
	{
		cout << "Error in intPosPow(int,int): both arguments shuld be 'positive' integers." << endl;
		return 0;
	}
	else if ( b==1 )
		result = a;
	else
		for (int i = 0; i < b; i++)
			result *= a;
	return result;
}

unsigned __int64 twoToThePowerOf (int power) //throw (exception)
{
	unsigned __int64 result = 1;
	if (power == 0)
		return 1;
	if (power < 0)
	{
		cerr << "Error in unsigned __int64 twoToThePowerOf (int): the parameter be a 'positive' integers." << endl;
		return 0;
	}
	exception e("Out of computing power exception");
	if (power > 63)
		throw (e);
	for (int i = 0; i < power; i++)
		result *= 2;
	return result;
}


void txt2bmp_bw (string sourceName, string targetName)
{
	CBitmap resultBMP (targetName);
	int rowNum = resultBMP.GetHeight();
	int colNum = resultBMP.GetWidth();
	int row = 0, col = 0;
	assert (colNum == MCOLS && rowNum == MROWS);
	ifstream inputFile(sourceName.data());
	////cutdown
	//ofstream outTextFile;
	//outTextFile.open("image1b_bit0.txt");
	//outTextFile.clear();
	////cutup
	int charCounter = 0;
	if (inputFile.is_open())
	{
		char character;
		while (inputFile.good() && row < rowNum - 1 && col < colNum)
		{
			row = charCounter / colNum;
			col = charCounter % colNum;
			do
			{
				inputFile >> character;
			}
			while (character == 0 || character == 1);
			////cutdown
			//if (col == 0 ) 
			//	outTextFile << endl;
			//outTextFile << character;
			////cutup
			
			if (character == '0')
				resultBMP.setWhiteRC(row, col);
			else if (character == '1')
				resultBMP.setBlackRC(row, col);
			else
				cout << "Then what the hell is the color?";
			charCounter++;
		}
	}

	else
		cout << "\nError: File " << sourceName << " could not be opened.\n";

	//outTextFile.close();
	inputFile.close();
	resultBMP.Save(targetName, 8u);
}

void setImageToBlack (string imageFileName)
{
	CBitmap image (imageFileName);
	int rowNum = image.GetHeight();
	int colNum = image.GetWidth();
	for (int row = 0; row < rowNum; row++)
		for (int col = 0; col < colNum; col++)
			image.setBlackRC(row,col);

	image.Save(imageFileName, 8U);
}

void setImageToWhite (string imageFileName)
{
	CBitmap image (imageFileName);
	int rowNum = image.GetHeight();
	int colNum = image.GetWidth();
	for (int row = 0; row < rowNum; row++)
		for (int col = 0; col < colNum; col++)
			image.setWhiteRC(row,col);

	image.Save(imageFileName, 8U);
}

void bmp2txt (string sourceName, string targetName, string component)
{
	CBitmap image (sourceName);
	ofstream outputTextFile;
	outputTextFile.open(targetName.data());
	outputTextFile.clear();
	int rowNum = image.GetHeight();
	int colNum = image.GetWidth();
	int r,b,g,a;
	double intensity;
	
	if (component == "average")
	{
		for (int row = 0; row < rowNum; row++)
		{
			for (int col = 0; col < colNum; col++)
			{
				r = image.redInRCPixel(row, col);
				g = image.greenInRCPixel(row, col);
				b = image.blueInRCPixel(row,col);
				a = image.alphaInRCPixel(row, col);
				intensity = (r+g+b)/3;
				outputTextFile << intensity << "\t";
			}
			outputTextFile << endl;
		}
	}
	else if (component == "red")
	{
		for (int row = 0; row < rowNum; row++)
		{
			for (int col = 0; col < colNum; col++)
			{
				r = image.redInRCPixel(row, col);
				outputTextFile << r << "\t";
			}
			outputTextFile << endl;
		}
	}
	else if (component == "green")
	{
		for (int row = 0; row < rowNum; row++)
		{
			for (int col = 0; col < colNum; col++)
			{
				g = image.greenInRCPixel(row, col);
				outputTextFile << g << "\t";
			}
			outputTextFile << endl;
		}
	}
	else if (component == "blue")
	{
		for (int row = 0; row < rowNum; row++)
		{
			for (int col = 0; col < colNum; col++)
			{
				b = image.blueInRCPixel(row, col);
				outputTextFile << b << "\t";
			}
			outputTextFile << endl;
		}
	}
	else
		cout << "Invalid color was specified in the input of free function bmp2txt(). valid values for color are average, red, green, blue; all lower case.\n";
	outputTextFile.close();
}

void bmp2txt_rgb (string sourceName, string targetName)
{
	CBitmap image (sourceName);
	ofstream outputTextFile;
	outputTextFile.open(targetName.data());
	outputTextFile.clear();
	int rowNum = image.GetHeight();
	int colNum = image.GetWidth();
	outputTextFile << "Red values:" << endl;
	for (int row = 0; row < rowNum; row++)
	{
		for (int col = 0; col < colNum; col++)
			outputTextFile << image.redInRCPixel(row, col) << "\t";
		outputTextFile << endl;
	}

	outputTextFile << "Green values:" << endl;
	for (int row = 0; row < rowNum; row++)
	{
		for (int col = 0; col < colNum; col++)
			outputTextFile << image.greenInRCPixel(row, col) << "\t";
		outputTextFile << endl;
	}

	outputTextFile << "Blue values:" << endl;
	for (int row = 0; row < rowNum; row++)
	{
		for (int col = 0; col < colNum; col++)
			outputTextFile << image.blueInRCPixel(row, col) << "\t";
		outputTextFile << endl;
	}

	outputTextFile << "Alpha values:" << endl;
	for (int row = 0; row < rowNum; row++)
	{
		for (int col = 0; col < colNum; col++)
			outputTextFile << image.alphaInRCPixel(row, col) << "\t";
		outputTextFile << endl;
	}
	outputTextFile.close();
}

/** I guess it converts a .txt file representing the pixels of an image to a .bmp file.*/
void txt2bmp (string sourceName, string targetName, string color)
{
	CBitmap resultBMP (targetName);
	int rowNum = resultBMP.GetHeight();
	int colNum = resultBMP.GetWidth();
	int row = 0, col = 0;
	assert (colNum == MCOLS && rowNum == MROWS);
	ifstream inputFile(sourceName.data());

	if (inputFile.is_open())
	{
		int value;
		if (color == "gray")
			for (int row = 0; row < rowNum; row++)
				for (int col = 0; col < colNum; col++)
				{
					inputFile >> value;
					resultBMP.setGrayRC(value, row, col);
				}
		else if (color == "red")
			for (int row = 0; row < rowNum; row++)
				for (int col = 0; col < colNum; col++)
				{
					inputFile >> value;
					resultBMP.setRedRC(value, row, col);
				}
		else if (color == "green")
			for (int row = 0; row < rowNum; row++)
				for (int col = 0; col < colNum; col++)
				{
					inputFile >> value;
					resultBMP.setGreenRC(value, row, col);
				}
		else if (color == "blue")
			for (int row = 0; row < rowNum; row++)
				for (int col = 0; col < colNum; col++)
				{
					inputFile >> value;
					resultBMP.setBlueRC(value, row, col);
				}

		//for (int row = 0; row < rowNum; row++)
		//	for (int col = 0; col < colNum; col++)
		//	{
		//		inputFile >> value;
		//		if (color == "gray")
		//			resultBMP.setGrayRC(value, row, col);
		//		else if (color == "red")
		//			resultBMP.setRedRC(value, row, col);
		//		else if (color == "green")
		//			resultBMP.setGreenRC(value, row, col);
		//		else if (color == "blue")
		//			resultBMP.setBlueRC(value, row, col);
		else
			cout << "Invalid color was specified in the input of free function txt2bmp(). valid values for color are gray, red, green, blue; all lower case.\n";
	}

	else
		cout << "\nError: File " << sourceName << " could not be opened.\n";

	//outTextFile.close();
	inputFile.close();
	resultBMP.Save(targetName/*, 8u*/);
}


void separateImageBits (string sourceName, string type, int layers)
{
	assert ( (type=="bmp" || type=="txt") && "the only valid types are bmp and txt, all lower case.");
	
	CBitmap image(sourceName + ".bmp");
	image.separateBits(sourceName, type, layers);
}


string int2Str(int number)
{
	stringstream ss;//create a stringstream
	ss << number;//add number to the stream
	return ss.str();//return a string with the contents of the stream
}

int str2Int(string str)
{
	int result = 0;
	stringstream ss;
	ss << str;
	ss >> result;
	return result;
}

void fillInRandomPermutationArray(int* permArray, int arraySize)
{
	int* sourceArray = new int[arraySize];
	for (int i = 0; i < arraySize; ++i)
		sourceArray[i] = i;

	for (int i = 0; i < arraySize; ++i)
	{
		int targetRank = rand() % (arraySize - i); //#of elements we have to choose from at this step: arraySize - 1
		int targetLocation = 0;
		for (int sourceArrayStep = 0; sourceArrayStep < targetRank; ++sourceArrayStep)
		{
			if (sourceArray[sourceArrayStep] == -1) //jump over already selected ones.
				++targetLocation;
			++targetLocation;
		}
		while (sourceArray[targetLocation] == -1)
			++targetLocation;

		//targetLocation has the value to be placed in the next permArray
		permArray[i] = sourceArray[targetLocation];
		sourceArray[targetLocation] = -1;
	}
	delete[] sourceArray;
}

bool binary(int num, int arraySize, bool* buffer) 
{
	if (pow((double)2, arraySize) < num)
	{
		assert ("The given integer number does not fit in the given binary array size!");
		return false;
	}
	//bool* result = new bool[arraySize];
	for (int i = 0; i < arraySize-1; i++)
	{
		buffer[i] = (num%2 == 1);
		num /= 2;
	}
	buffer[arraySize-1] = (num == 1);
	return true;
}

bool longBinary(unsigned __int64 num, int arraySize, bool* buffer) 
{
	//if (pow((double)2, arraySize) < num)
	if (twoToThePowerOf(arraySize) < num)
	{
		assert ("The given integer number does not fit in the given binary array size!");
		return false;
	}
	//bool* result = new bool[arraySize];
	for (int i = 0; i < arraySize-1; i++)
	{
		buffer[i] = (num%2 == 1);
		num /= 2;
	}
	buffer[arraySize-1] = (num == 1);
	return true;
}